<template>
  <ScreenAdapter>
    <div class="page">
      <!-- 团课背景图 -->
      <img :src="info.teamBackgroundImage" class="bg" />
      <!-- 右侧团课信息 -->
      <div class="left">
        <el-select v-model="defaultStoreSign" placeholder="Select" size="large">
          <el-option v-for="item in storeList" :key="item" :label="item.name" :value="item.sign" />
        </el-select>
        <div class="time">{{ newDate }}</div>
        <div class="btn" @click="() => {this.$router.push('/ranking')}">{{ info.teamName }}</div>
        <div class="code">
          <img :src="localQrUrl" width="100%" />
          <div>扫码加入团课</div>
        </div>
        <div class="level" v-for="(item, idx) in info.intensityData" :key="idx">
          <div :style="`background: ${item.color}`" class="bg" />
          <div style="position: relative; z-index: 1;">
            <img :src="item.icon" />
            <span>{{ item.intensity }}</span>
          </div>
        </div>
        <div class="btnBox">
          <div class="btn">配置</div>
          <div class="btn" @click="grid = grid == 6 ? 2 : grid + 1">画面</div>
        </div>
      </div>
      <!-- 左侧列表 -->
      <div class="right" :style="`gap: ${style[grid-2].gap}px;`">
        <div v-for="item, key in localUserList" :key="key" :style="{
          width: `${style[grid-2].width}px`,
          height: `${style[grid-2].height}px`,
          backgroundImage: `url(${require(`@/assets/rate/${boxBgImg[item.background]}.png`)})`
        }">
          <div class="scale" :style="`transform: translate(0, 0) scale(${style[grid-2].scale});transform-origin: top left;`">
            <div class="content">
              <!-- 会员信息 -->
              <div class="time">
                <div class="avatar">
                  <img :src="item.avatar" height="134px" width="134px" style="border-radius: 100%;" />
                  <label>{{ item.nickname }}</label>
                </div>
                <div>
                  <div class="time_left">
                    <div class="title">{{sportType ? '上' : '本'}}周运动</div>
                    <div>
                      <img src="@/assets/rate/count.png" height="42px" />
                      <span>{{ item[typeField[sportType]+'Time'] }}min</span>
                    </div>
                    <div class="progress" style="margin-bottom: 25px;">
                      <div :style="`width: ${item[typeField[sportType]+'TimeProgress']}%`" />
                      <label v-if="item[typeField[sportType]+'TimeProgress'] == 100" style="right: 0;color: #000;">已达标</label>
                      <label v-else :style="`left: ${item[typeField[sportType]+'TimeProgress']}%`">未达标</label>
                    </div>
                    <div>
                      <img src="@/assets/rate/time.png" height="42px" />
                      <span>{{ item[typeField[sportType]+'Count'] }}次</span>
                    </div>
                    <div class="progress">
                      <div :style="`width: ${item[typeField[sportType]+'CountProgress']}%`" />
                      <label v-if="item[typeField[sportType]+'CountProgress'] == 100" style="right: 0;color: #000;">已达标</label>
                      <label v-else :style="`left: ${item[typeField[sportType]+'CountProgress']}%`">未达标</label>
                    </div>
                  </div>
                  <div class="time_right">
                    <div>
                      <img src="@/assets/rate/icon-fire.png" height="41px" style="margin-left: 4px;" />
                      <span style="width: 160px;">{{ item.calorie }}kcal</span>
                    </div>
                    <div>
                      <img src="@/assets/rate/icon-time.png" height="42px" />
                      <span>{{ item.time }}</span>
                    </div>
                    <div v-if="item.blood_sugar" @click="charLineHeartRate(item.userSign)">
                      <img :src="require(`@/assets/rate/icon_sugar${item.bloodSugarIsOnline ? '' : '_gery'}.png`)" height="42px" />
                      <p>{{ item.blood_sugar }}</p>
                      <img :src="require(`@/assets/rate/icon_${item.blood_sugar_trend ? item.blood_sugar_trend == 1 ? 'down' : 'up' : 'nochange'}.png`)" width="45px" />
                    </div>
                  </div>
                </div>
              </div>
              <!-- 心率 -->
              <div class="realTime">
                <div class="fatBurn" :style="`background-image: url(${require(`@/assets/rate/${boxBgImg[item.background]}_btn.png`)})`">
                  <img src="@/assets/rate/burning.png" height="30px" />{{ item.fat_burning }}g
                </div>
                <div class="rate">
                  <img src="@/assets/rate/heart-circle.png" width="250px" />
                  <div>
                    <img src="@/assets/rate/icon_rate.png" height="30px" />
                    <div>{{ item.heart_rate }}</div>
                    <label>bpm</label>
                  </div>
                </div>
                <div class="intensity">
                  <div style="border-right: 2px solid;">
                    <p>{{ item.sportBeforeBloodPressure }}</p>当前血压
                  </div>
                  <div>
                    <p>{{ item.safeSportIntensity }}</p>心率有效范围
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </ScreenAdapter>
  <el-dialog title="动态血糖+运动强度曲线图" v-model="dialogVisible" width="896px" header-class="headerDialog">
    <div ref="chartRef" style="height: 500px;margin-top: 70px;padding-bottom: 15px;" />
  </el-dialog>
</template>

<script>
import ScreenAdapter from '../../components/ScreenAdapter';
import { getInfo, getStoreList, saveRecord, getChartDate } from '@/api';
import { ElSelect, ElOption, ElLoading, ElDialog } from 'element-plus';
import * as echarts from "echarts";
let loadingInstance, beginTime;
export default {
  name: "HeartRateMonitor",
  components: { ElSelect, ElOption, ScreenAdapter, ElDialog },
  data() {
    return {
      height: window.innerHeight,
      localQrUrl: '',
      newDate: '',
      info: {},
      ws: null,
      isConnected: false,
      heartbeatTimer: null,
      reconnectTimer: null,
      reconnectAttempts: 0,
      maxReconnectAttempts: 5,
      grid: 2,
      localUserList: [],
      style: [
        {width: 782, height: 491, gap: 30, scale: 1},
        {width: 518, height: 326, gap: 20, scale: 0.66},
        {width: 383.5, height: 240, gap: 20, scale: 0.489},
        {width: 310.8, height: 196, gap: 10, scale: 0.399},
        {width: 257, height: 161, gap: 10, scale: 0.329},
      ],
      listLength: 0,
      boxBgImg: {
        '#E6562F': 'high',
        '#A32181': 'm_high+',
        '#F1933B': 'm_high',
        '#EFC444': 'medium',
        '#8DD146': 'm_low',
        '#4CC132': 'low'
      },
      storeList: [],
      defaultStoreSign: null,
      dialogVisible: false,
      sportType: 0,
      typeField: ['weekSport', 'lastWeekSport']
    }
  },
  created() {
    this.getStore();
    this.updateTime();
    setInterval(this.updateTime, 60000);
    this.initWebSocket(); // 获取上课人员心率数据
    // 监听关闭浏览器保存数据
    window.addEventListener('beforeunload', this.getDate)
    window.addEventListener('unload', this.save)
    // 10秒切换上周和本周运动数据
    setInterval(() => {
      this.sportType = this.sportType ? 0 : 1
    }, 10000)
  },
  watch: {
    listLength(len) {
      this.grid = len <= 4 ? 2 : len <= 9 ? 3 : len <= 16 ? 4 : len <= 25 ? 5 : 6;
    },
    defaultStoreSign(val) {
      localStorage.setItem('defaultStoreSign', val)
      this.getBase(val)
    }
  },
  beforeUnmount() {
    this.closeWebSocket();
    // 移除浏览器监听
    window.removeEventListener('beforeunload', this.getDate)
    window.addEventListener('unload', this.save)
  },
  methods: {
    // 获取当前时间
    getDate() {
      beginTime = new Date().getTime()
    },
    // 提示后端保存数据
    save() {
      const differTime = new Date().getTime() - beginTime
      if(differTime <= 5) saveRecord({sign: this.info.teamSign})
    },
    // 获取门店列表
    async getStore() {
      const location = JSON.parse(localStorage.getItem('geolocation'))
      getStoreList(location).then(res => {
        this.storeList = res
        const defaultSign = localStorage.getItem('defaultStoreSign')
        let sign = ''
        if(defaultSign && defaultSign != 'null' && defaultSign != 'undefined') {
          const item = res.find(v => v.sign == defaultSign)
          if(item) {
            sign = item.sign
          }
        }
        this.defaultStoreSign = sign || res[0].sign || ''
      })
    },
    // 获取门店团课信息
    getBase(storeSign) {
      loadingInstance = ElLoading.service({ fullscreen: true })
      getInfo({ storeSign }).then(res => {
        const { qrCode } = res
        // 处理二维码数据
        if (qrCode) {
          this.localQrUrl = qrCode.startsWith("data:image") ? qrCode : `data:image/png;base64,${qrCode}`
        }
        this.info = res
        setTimeout(() => {
          loadingInstance.close()
        }, 200)
      })
    },
    // WebSocket连接
    initWebSocket() {
      try {
        this.ws = new WebSocket("wss://saas.hansifit.com/JbvZhE?");
        this.ws.onopen = () => {
          console.log("WebSocket连接已建立");
          this.isConnected = true;
          this.reconnectAttempts = 0;
          this.startHeartbeat();
        };

        this.ws.onmessage = (event) => {
          const data = JSON.parse(event.data);
          console.log("收到WebSocket消息:", data);
          if (data.event === "pong") {
            // 处理心跳响应
            console.log("收到心跳响应");
          } else if (data.event === "heartRateMianMonitor") {
            // 处理心率数据
            this.listLength = data.data.length;
            this.localUserList = data.data
          }
        };

        this.ws.onclose = () => {
          console.log("WebSocket连接已关闭");
          this.isConnected = false;
          this.stopHeartbeat();
          this.reconnect();
        };

        this.ws.onerror = (error) => {
          console.error("WebSocket错误:", error);
          this.isConnected = false;
        };
      } catch (error) {
        console.error("WebSocket初始化错误:", error);
        this.reconnect();
      }
    },
    startHeartbeat() {
      this.heartbeatTimer = setInterval(() => {
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
          const heartbeat = {
            data: {},
            event: "ping",
            sign: this.info.teamSign, // 使用teamSign作为心跳包的sign参数
          };
          this.ws.send(JSON.stringify(heartbeat));
        }
      }, 1000); // 每1秒发送一次心跳
    },
    // 关闭连接
    closeWebSocket() {
      this.stopHeartbeat();
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer);
      }
      if (this.ws) {
        this.ws.close();
      }
    },
    // 关闭心跳
    stopHeartbeat() {
      if (this.heartbeatTimer) {
        clearInterval(this.heartbeatTimer);
        this.heartbeatTimer = null;
      }
    },
    // 重新连接
    reconnect() {
      if (this.reconnectAttempts < this.maxReconnectAttempts) {
        this.reconnectAttempts++;
        console.log(
          `尝试重新连接 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`
        );

        this.reconnectTimer = setTimeout(() => {
          this.initWebSocket();
        }, 5000); // 5秒后重试
      } else {
        console.error("达到最大重连次数，停止重连");
      }
    },
    // 获取实时时间
    updateTime() {
      const now = new Date();
      this.newDate = `${now.getHours().toString().padStart(2, "0")}:${now
      .getMinutes() 
      .toString()
      .padStart(2, "0")}`;
    },
    // 动态血糖曲线
    async charLineHeartRate(userSign) {
      const result = await getChartDate({ userSign, teamSign: this.info.teamSign })
      this.dialogVisible = true
      this.$nextTick(() => {
        const myChart = echarts.init(this.$refs.chartRef), markLine = [];
        // 警戒线
        [3.9, 11.1, 7.8, 8.6].forEach(v => {
          const color = (v == 7.8 || v == 8.6) ? '#a0a0a0' : '#ff6b6b'
          const obj = {
            symbol: false,
            yAxis: v,
            emphasis: {
              lineStyle: { width: 1.5 }
            },
            lineStyle: { width: 1.5 },
            itemStyle: { color },
            label: {
              formatter(value) {
                let str = value.value
                if(v == 3.9 || v == 11.1) {
                  str = `${v == 3.9 ? '低' : '高'}血糖警戒值${value.value}mmol/L`
                }
                return str
              },
              show: true,
              position: 'insideStartTop',
              fontFamily: 'PingFang SC',
              fontSize: 16,
              color
            }
          }
          markLine.push(obj)
        })
        // y坐标轴
        const yAxis = [];
        ['mmol/L', 'bpm'].forEach(v => {
          const obj = {
            type: 'value',
            nameGap: 25,
            name: `(${v})`,
            alignTicks: true,
            nameTextStyle: {
              fontSize: 15,
              color: '#666',
              align: v == 'bpm' && 'left'
            },
            axisLine: {
              show: true, 
              lineStyle: {
                color: '#f2f2f2'
              }
            },
            axisLabel: {
              fontSize: 15,
              margin: 15
            },
            splitLine: {
              show: v == 'mmol/L',
              lineStyle: {
                color: '#f2f2f2'
              }
            },
            max: 15
          }
          if(v == 'bpm') {
            obj.max = 180,
            obj.min = 30
          }
          yAxis.push(obj)
        })
        // 心率图颜色区分
        const pieces = []
        result.strength.map((v, k) => {
          const obj = {gt: v.leftRange, lte: v.rangeRange, color: v.color}
          v.leftRange ==  v.rangeRange && delete(obj[k == 0 ? 'gt' : 'lte'])
          pieces.push(obj)
        })
        // 图表基础配置
        const min = result.startTime * 1000, max = result.endTime * 1000;
        const option = {
          grid: { 
            containLabel: true,
            left: 20,
            right: 20,
            top: 40,
            bottom: 0,
            heigth: '100%'
          },
          tooltip: { trigger: 'axis' },
          xAxis: [{
            type: 'time',
            min,
            max,
            boundaryGap: false,
            axisLine: {show: false},
            axisTick: {show: false},
            alignTicks: true,
            axisLabel: {
              fontSize: 15,
              margin: 20,
              showMaxLabel: true,
              showMinLabel: true,
              formatter(value) {
                return echarts.format.formatTime('hh:mm', value);
              }
            }
          }, {
            type: 'time',
            min: result.startTime * 1000 - 24 * 60 * 60 * 1000,
            max: result.endTime * 1000 - 24 * 60 * 60 * 1000,
            alignTicks: true,
            boundaryGap: false,
            axisLine: {show: false},
            axisLabel: {
              show: false,
              showMaxLabel: true,
              showMinLabel: true
            },
            axisTick: {show: false}
          }],
          yAxis,
          visualMap: [{
            seriesIndex: 0,
            show: false,
            pieces: [
              {gt: 11.1, color: '#ff6b6b'}, 
              {gt: 3.9, lte: 11.1, color: '#333742'},
              {lt: 3.9, color: '#ff6b6b'}
            ]
          }, {
            seriesIndex: 2,
            show: false,
            pieces
          }],
          series: [{
            type: 'line',
            name: 'mmol/L',
            yAxisIndex: 0,
            xAxisIndex: 0,
            zlevel: 2,
            smooth: true,
            showSymbol: false,
            data: result.todayglucose,
            lineStyle: { width: 3 },
            markLine: { data: markLine }
          }, {
            type: 'line',
            emphasis: {
              lineStyle: {
                color: '#dedfe1'
              }
            },
            name: 'mmol/L',
            zlevel: 1,
            yAxisIndex: 0,
            smooth: true,
            showSymbol: false,
            data: result.yesterdayglucose,
            xAxisIndex: 1,
            itemStyle: { color: '#dedfe1' }
          }, {
            type: 'bar',
            barWidth: '100%',
            zlevel: 0,
            yAxisIndex: 1,
            xAxisIndex: 0,
            name: 'bpm',
            smooth: true,
            showSymbol: false,
            data: result.heartRate,
            areaStyle: {}
          }
        ]}
        option && myChart.setOption(option)
      })
    }
  }
};
</script>

<style scoped lang="scss">
:deep(.el-select--large .el-select__wrapper) {
  line-height: 38px;
  font-size: 17px;
  min-height: 54px;
  font-weight: bold;
  border-radius: 10px;
}
.left {
  text-align: center;
  width: 236px;
  .level {
    height: 62px;
    line-height: 62px;
    font-size: 24px;
    margin-bottom: 10px;
    padding-left: 29px;
    text-align: left;
    position: relative;
    .bg {
      height: 100%;
      width: 100%;
      left: 0;
      border-radius: 10px;
      position: absolute;
      opacity: .7;
      z-index: 0;
    }
    img {
      margin-right: 13px;
      height: 26px;
      vertical-align: middle;
    }
  }
  .time {
    font-size: 36px;
    margin: 29px 0;
  }
  .btn {
    height: 53px;
    line-height: 53px;
    font-size: 24px;
    border-radius: 10px;
    cursor: pointer;
    background: linear-gradient(90deg, #59B2FF 0%, #344199 100%);
  }
  .code {
    padding: 10px;
    background: #fff;
    border-radius: 10px;
    font-size: 18px;
    color: #000;
    margin: 20px 0;
  }
  .btnBox {
    display: flex;
    gap: 10px;
    padding-top: 10px;
    div {
      width: 50%;
      height: 63px;
      line-height: 63px;
    }
  }
}
.page {
  width: 100%;
  height: 100%;
  padding: 30px;
  background: rgba(18, 17, 17, 0.3);
  font-family: 'SimHei', '黑体', sans-serif;
  display: flex;
  gap: 30px;
  color: #fff;
  align-items: flex-start;
  .bg {
    position: fixed;
    width: 100%;
    height: 100%;
    z-index: -1;
    left: 0;
    top: 0;
  }
}
.right {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  > div {
    position: relative;
    background-repeat: no-repeat;
    background-size: 100% 100%;
  }
  .bg {
    border-radius: 9.44px;
    z-index: 0;
    position: absolute;
    opacity: .7;
  }
  .scale {
    padding: 38px 45px; // 44px 108px 33px 76px
    position: relative;
    width: 100%;
    height: 100%;
    width: 782px;
    height: 491px;
  }
  .content {
    display: flex;
    justify-content: space-between;
    position: relative;
    z-index: 2;
  }
}
.time {
  > div, &_right > div, &_left > div:not(.title) {
    display: flex;
    align-items: center;
  }
  &_right > div:nth-child(2) {
    margin: 40px 0;
  }
  &_left {
    border: 1px solid #fff;
    margin-right: 40px;
    padding: 20px 15px;
    border-radius: 20px;
    width: 196px;
  }
  .progress {
    margin-top: 10px;
    border: 2px solid;
    position: relative;
    label {
      position: absolute;
      border: 1px solid #000;
      font-size: 12px;
      display: inline-block;
      width: 44px;
      text-align: center;
      background: #fff;
      border-radius: 10px;
      color: #f00;
      padding: 4px 0;
    }
    div {
      height: 10px;
      background: #5f99d6;
    }
  }
  .title {
    text-align: center;
    font-size: 26px;
    margin-bottom: 18px;
  }
  .avatar {
    gap: 20px;
    margin: 5px 0 30px 0;
  }
  label {
    display: block;
    font-size: 30px;
  }
  span, p {
    font-size: 34px;
    padding-left: 20px;
  }
  p {
    padding-right: 15px;
    text-align: left;
  }
}
.intensity, .fatBurn {
  background-size: 100% 100%;
  background-repeat: no-repeat;
  margin: auto;
}
.fatBurn {
  height: 55px;
  font-size: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 15px;
  width: 150px;
}
.intensity {
  text-align: center;
  font-weight: bold;
  letter-spacing: 1px;
  background-image: linear-gradient(to right,#96d21766,rgba(237,124,18,.4),#ed401366);
  border: 2px solid;
  border-radius: 10px;
  display: flex;
  div {
    padding: 8px;
  }
  p {
    font-size: 27px;
    line-height: 1;
  }
  width: fit-content;
}
.rate {
  position: relative;
  font-size: 0;
  margin: 25px 0;
  > div {
    position: absolute;
    width: 100%;
    top: 20%;
    text-align: center;
    font-size: 8px;
    line-height: 1;
    div {
      font-size: 85px;
      margin: 6px 0 7px 0;
    }
    label {
      font-size: 24px;
    }
  }
}
</style>
<style lang="scss">
.headerDialog {
  background: linear-gradient(90deg, #59B2FF 0%, #344199 100%);
  color: #fff;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  padding: 16px 24px;
  border-radius: 5px 5px 0 0;
  .el-dialog__title, .el-dialog__close {
    color: #fff;
    font-weight: bold;
  }
}
</style>
